home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / interp / driver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-15  |  7.9 KB  |  364 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: driver.c,v 1.16 94/10/05 21:01:46 nkramer Exp $
  27. *
  28. * Main driver routines for mindy.
  29. *
  30. \**********************************************************************/
  31.  
  32. #include "../compat/std-c.h"
  33. #include "../compat/std-os.h"
  34.  
  35. #include <setjmp.h>
  36.  
  37. #include "mindy.h"
  38. #include "gc.h"
  39. #include "thread.h"
  40. #include "driver.h"
  41. #include "bool.h"
  42. #include "gc.h"
  43. #if SLOW_FUNCTION_POINTERS
  44. #include "interp.h"
  45. #endif
  46.  
  47. static boolean InInterpreter = FALSE;
  48. static jmp_buf Catcher;
  49. static enum pause_reason PauseReason;
  50.  
  51. #define OPS_PER_TIME_SLICE 100
  52.  
  53.  
  54. /* signal handling. */
  55. static void (*SignalHandlers[NSIG])(void) = {0};
  56. static boolean SignalPending[NSIG] = {0};
  57. static boolean SignalAction[NSIG] = {0};
  58. static boolean SignalBlocked[NSIG] = {0};
  59.  
  60. static void signal_handler(int sig)
  61. {
  62.     if (SignalHandlers[sig]) {
  63.         SignalBlocked[sig] = TRUE;
  64.     SignalHandlers[sig]();
  65.         SignalBlocked[sig] = FALSE;
  66.     } else
  67.     SignalPending[sig] = TRUE;
  68. }  
  69.  
  70. void set_signal_handler(int sig, void(*handler)(void))
  71. {
  72.     SignalHandlers[sig] = handler;
  73.     if (SignalPending[sig]) {
  74.         SignalPending[sig] = FALSE;
  75.     handler();
  76.     }
  77.     if ( ! SignalAction[sig]) {
  78.         struct sigaction sa = { 0 };
  79.     sa.sa_handler = signal_handler;
  80.     sigaction(sig, &sa, NULL);
  81.     SignalAction[sig] = TRUE;
  82.     }
  83.     if (SignalBlocked[sig])
  84.       unblock_signal_handler(sig);
  85. }
  86.  
  87. void clear_signal_handler(int sig)
  88. {
  89.     SignalHandlers[sig] = NULL;
  90.     if (SignalBlocked[sig])
  91.       unblock_signal_handler(sig);
  92. }
  93.  
  94. void unblock_signal_handler(int sig)
  95. {
  96.   sigset_t set;
  97.  
  98.   SignalBlocked[sig] = FALSE;
  99.   sigemptyset(&set);
  100.   sigaddset(&set, sig);
  101.   sigprocmask(SIG_UNBLOCK, &set, NULL);
  102. }
  103.  
  104. /* SIGINT handling. */
  105.  
  106. void set_interrupt_handler(void (*handler)(void))
  107. {
  108.     set_signal_handler(SIGINT, handler);
  109. }
  110.  
  111. void clear_interrupt_handler(void)
  112. {
  113.     clear_signal_handler(SIGINT);
  114. }
  115.  
  116. void unblock_interrupt_handler(void)
  117. {
  118.     unblock_signal_handler(SIGINT);
  119. }
  120.  
  121. /* Waiting on file descriptors. */
  122.  
  123. static struct waiters {
  124.     fd_set fds;
  125.     obj_t events[FD_SETSIZE];
  126. } Readers, Writers;
  127. static int NumFds;
  128.  
  129. static void check_fds(boolean block)
  130. {
  131.     fd_set readfds, writefds;
  132.     int nfound, fd;
  133.     struct timeval tv, *tvp;
  134.  
  135.     if (NumFds == 0) {
  136.     if (block)
  137.       sigsuspend(0);
  138.     return;
  139.     }
  140.  
  141.     memcpy(&readfds, &Readers.fds, sizeof(readfds));
  142.     memcpy(&writefds, &Writers.fds, sizeof(writefds));
  143.  
  144.     if (block)
  145.     tvp = NULL;
  146.     else {
  147.     tv.tv_usec = 0;
  148.     tv.tv_sec = 0;
  149.     tvp = &tv;
  150.     }
  151.  
  152.     nfound = select(NumFds, &readfds, &writefds, NULL, tvp);
  153.  
  154.     if (nfound < 0) {
  155.     switch (errno) {
  156.       case EBADF:
  157.         /* One of the file descriptors when bad.  Wake everyone up */
  158.         /* and let the individual threads figure out who is selecting */
  159.         /* on a bogus fd. */
  160.         for (fd = 0; fd < NumFds; fd++) {
  161.         if (FD_ISSET(fd, &Readers.fds))
  162.             event_broadcast(Readers.events[fd]);
  163.         if (FD_ISSET(fd, &Writers.fds))
  164.             event_broadcast(Writers.events[fd]);
  165.         }
  166.         FD_ZERO(&Readers.fds);
  167.         FD_ZERO(&Writers.fds);
  168.         NumFds = 0;
  169.         break;
  170.         
  171.       case EINTR:
  172.         break;
  173.       case EINVAL:
  174.         lose("select failed with EINVAL?");
  175.     }
  176.     }
  177.     else if (nfound > 0) {
  178.     for (fd = 0; fd < NumFds; fd++) {
  179.         if (FD_ISSET(fd, &readfds)) {
  180.         event_broadcast(Readers.events[fd]);
  181.         FD_CLR(fd, &Readers.fds);
  182.         }
  183.         if (FD_ISSET(fd, &writefds)) {
  184.         event_broadcast(Writers.events[fd]);
  185.         FD_CLR(fd, &Writers.fds);
  186.         }
  187.     }
  188.     for (fd = NumFds - 1; fd >= 0; fd--)
  189.         if (FD_ISSET(fd, &Readers.fds) || FD_ISSET(fd, &Writers.fds))
  190.         break;
  191.     NumFds = fd+1;
  192.     }
  193. }
  194.  
  195. static void wait_for_fd(struct thread *thread, int fd, struct waiters *waiters,
  196.             void (*advance)(struct thread *thread))
  197. {
  198.     obj_t event;
  199.  
  200.     FD_SET(fd, &waiters->fds);
  201.  
  202.     if (NumFds <= fd)
  203.     NumFds = fd+1;
  204.  
  205.     event = waiters->events[fd];
  206.     if (event == obj_False) {
  207.     event = make_event();
  208.     waiters->events[fd] = event;
  209.     }
  210.  
  211.     event_wait(thread, event, obj_False, advance);
  212. }
  213.  
  214. void wait_for_input(struct thread *thread, int fd,
  215.             void (*advance)(struct thread *thread))
  216. {
  217.     wait_for_fd(thread, fd, &Readers, advance);
  218. }
  219.  
  220. void wait_for_output(struct thread *thread, int fd,
  221.              void (*advance)(struct thread *thread))
  222. {
  223.     wait_for_fd(thread, fd, &Writers, advance);
  224. }
  225.  
  226.  
  227.  
  228. /* Driver loop entry points. */
  229.  
  230. static void set_pause_interrupted(void)
  231. {
  232.     PauseReason = pause_Interrupted;
  233. }
  234.  
  235. enum pause_reason do_stuff(void)
  236. {
  237.     struct thread *thread;
  238.     volatile int timer;
  239.     volatile boolean do_select = TRUE;
  240.  
  241.     assert (!InInterpreter);
  242.  
  243.     do {
  244.     if (do_select)
  245.         check_fds(FALSE);
  246.     else
  247.         do_select = TRUE;
  248.     PauseReason = pause_NoReason;
  249.     thread = thread_pick_next();
  250.     if (thread) {
  251.         timer = OPS_PER_TIME_SLICE;
  252.         InInterpreter = TRUE;
  253.         set_interrupt_handler(set_pause_interrupted);
  254.         _setjmp(Catcher);
  255.         if (PauseReason == pause_NoReason)
  256.         while (timer-- > 0) {
  257. #if SLOW_FUNCTION_POINTERS
  258.             if (thread->advance)
  259.             thread->advance(thread);
  260.             else
  261.             interpret_next_byte(thread);
  262. #else
  263.             thread->advance(thread);
  264. #endif
  265.         }
  266.         InInterpreter = FALSE;
  267.         clear_interrupt_handler();
  268.  
  269.         if (TimeToGC)
  270.         collect_garbage();
  271.     }
  272.     else if (all_threads() == NULL)
  273.         PauseReason = pause_NothingToRun;
  274.     else {
  275.         set_interrupt_handler(set_pause_interrupted);
  276.         check_fds(TRUE);
  277.         do_select = FALSE;
  278.         clear_interrupt_handler();
  279.     }
  280.     } while (PauseReason == pause_NoReason
  281.          || PauseReason == pause_PickNewThread);
  282.     return PauseReason;
  283. }
  284.  
  285. enum pause_reason single_step(struct thread *thread)
  286. {
  287.     assert(!InInterpreter);
  288.     assert(thread->status == status_Running);
  289.     assert(thread->suspend_count == 0);
  290.  
  291.     check_fds(FALSE);
  292.  
  293.     thread_set_current(thread);
  294.     InInterpreter = TRUE;
  295.     PauseReason = pause_NoReason;
  296.     set_interrupt_handler(set_pause_interrupted);
  297.     if (_setjmp(Catcher) == 0) {
  298. #if SLOW_FUNCTION_POINTERS
  299.     if (thread->advance)
  300.         thread->advance(thread);
  301.     else
  302.         interpret_next_byte(thread);
  303. #else
  304.     thread->advance(thread);
  305. #endif
  306.     }
  307.     InInterpreter = FALSE;
  308.     clear_interrupt_handler();
  309.     if (TimeToGC)
  310.     collect_garbage();
  311.     return PauseReason;
  312. }
  313.  
  314. void go_on(void)
  315. {
  316.     assert(InInterpreter);
  317.     _longjmp(Catcher, 1);
  318. }
  319.  
  320. void pause(enum pause_reason reason)
  321. {
  322.     clear_interrupt_handler();
  323.     if (reason != pause_NoReason)
  324.     PauseReason = reason;
  325.     go_on();
  326. }
  327.  
  328.  
  329. /* GC stuff. */
  330.  
  331. static void scav_waiters(struct waiters *waiters)
  332. {
  333.     int fd;
  334.  
  335.     for (fd = 0; fd < FD_SETSIZE; fd++)
  336.     scavenge(waiters->events + fd);
  337. }
  338.  
  339. void scavenge_driver_roots(void)
  340. {
  341.     scav_waiters(&Readers);
  342.     scav_waiters(&Writers);
  343. }
  344.  
  345.  
  346. /* Init stuff. */
  347.  
  348. static void init_waiters(struct waiters *waiters)
  349. {
  350.     int fd;
  351.  
  352.     FD_ZERO(&waiters->fds);
  353.     for (fd = 0; fd < FD_SETSIZE; fd++)
  354.     waiters->events[fd] = obj_False;
  355. }
  356.  
  357. void init_driver()
  358. {
  359.     init_waiters(&Readers);
  360.     init_waiters(&Writers);
  361.     NumFds = 0;
  362.     set_interrupt_handler(NULL);
  363. }
  364.